package com.kosam.commons.base.util;

import com.kosam.commons.base.entity.BaseEntity;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import javax.persistence.Column;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.util.*;


/**
 * Created by tgx on 2017/2/20.
 */
public class CommonUtils {
    private static final String DateField = "Date";
    private static final String IDField = "id";
    private static final Logger log = LoggerFactory.getLogger(CommonUtils.class);

    public static PageRequest getPageable(String sortField, String sortOrder, int offset, int limit) {
        int page = (int) (offset / limit);
        Sort.Direction direction = Sort.Direction.ASC;
        if (Sort.Direction.DESC.toString().equals(sortOrder)) {
            direction = Sort.Direction.DESC;
        }
        PageRequest pageable = new PageRequest(page, (int) limit, direction, sortField);
        return pageable;
    }


    public static PageRequest getPageable(HttpServletRequest request, int offset, int limit, Class<?> clazz) {
        int page = (int) (offset / limit);
        PageRequest pageable = new PageRequest(page, (int) limit, CommonUtils.getSort(request, clazz));
        return pageable;
    }

    public static PageRequest getPageable(int offset, int limit) {
        int page = (int) (offset / limit);
        PageRequest pageable = new PageRequest(page, (int) limit);
        return pageable;
    }

    public static Sort getSort(String sortField, String sortOrder) {
        Sort sort = null;
        if (StringUtils.isNotBlank(sortField)) {
            Sort.Direction direction = Sort.Direction.ASC;
            if (Sort.Direction.DESC.toString().equalsIgnoreCase(sortOrder)) {
                direction = Sort.Direction.DESC;
            }
            sort = new Sort(direction, sortField);
        }
        return sort;
    }

    //id,name: asc;key: desc;
    public static Sort convertSort(String ordersStr, Class<?> clazz) {
        if (StringUtils.isBlank(ordersStr)) {
            return null;
        }
        List<Sort.Order> orderList = new ArrayList<Sort.Order>();
        String[] orders = ordersStr.split(";");
        for (String orderStr : orders) {
            String[] ss = orderStr.split(":");
            Sort.Direction direction = Sort.Direction.ASC;
            if (Sort.Direction.DESC.toString().equalsIgnoreCase(ss[1].trim())) {
                direction = Sort.Direction.DESC;
            }

            String column = CommonUtils.getColumn(clazz, ss[0].trim());
            if (StringUtils.isNotBlank(column)) {
                orderList.add(new Sort.Order(direction, column));
            }
        }
        if (orderList.isEmpty()) {
            return null;
        }
        return new Sort(orderList);
    }

    public static Sort getSort(HttpServletRequest request, Class<?> clazz) {
        Enumeration<String> parameterNames = request.getParameterNames();
        Map<String, String> map = new HashMap<>();
        String index = null;
        String direct = null;
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            if (name.matches("columns\\[\\w+\\]\\[name\\]")) {
                String value = request.getParameter(name);
                map.put(name, value);
            }
            if (name.matches("order\\[\\w+\\]\\[column\\]")) {
                index = request.getParameter(name);
            }
            if (name.matches("order\\[\\w+\\]\\[dir\\]")) {
                direct = request.getParameter(name);
            }
        }
        return convertSort(map.get("columns[" + index + "][name]") + ":" + direct, clazz);
    }


    public static String getColumn(Class<?> clazz, String field) {
        String column = null;
        if (BaseEntity.ID.equalsIgnoreCase(field)) {
            return BaseEntity.ID;
        }
        if (BaseEntity.CREATE_BY.equalsIgnoreCase(field)) {
            return "CREATE_BY";
        }
        if (BaseEntity.CREATE_DATE.equalsIgnoreCase(field)) {
            return "CREATE_DATE";
        }
        if (BaseEntity.LAST_MODIFIED_BY.equalsIgnoreCase(field)) {
            return "LAST_MODIFIED_BY";
        }
        if (BaseEntity.LAST_MODIFIED_DATE.equalsIgnoreCase(field)) {
            return "LAST_MODIFIED_DATE";
        }
        try {
            if (clazz.getDeclaredField(field) != null) {
                column = clazz.getDeclaredField(field).getAnnotation(Column.class).name();
            }
        } catch (Exception e) {
            try {
                column = clazz.getSuperclass().getDeclaredField(field).getAnnotation(Column.class).name();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return column;
    }


    public static void formatQueryParameter(Query query, Map<String, Object> paramMap) {
        if (paramMap == null || paramMap.isEmpty()) {
            return;
        }
        for (String param : paramMap.keySet()) {
            query.setParameter(param, paramMap.get(param));
        }
    }

    public static <T> T copyFromDbMap(Map<String, Object> map, T target) {
        Map<String, Object> newMap = new HashMap<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            //下划线分隔的字符串，转换为驼峰式字符串,例如：USER_NAME to userName
            StringBuilder keyBuilder = new StringBuilder();
            String[] keys = entry.getKey().split("_");
            keyBuilder.append(keys[0].toLowerCase()); //第一个单词小写
            for (int i = 1; i < keys.length; i++) {
                String key = keys[i];
                String temp = key.substring(0, 1).toUpperCase() + key.substring(1, keys[i].length()).toLowerCase(); //首字母大写，其它字母小写
                keyBuilder.append(temp);
            }
            Object value = entry.getValue() != null && entry.getValue() instanceof BigInteger ? ((BigInteger) entry.getValue()).longValue() : entry.getValue();
            newMap.put(keyBuilder.toString(), value);
        }
        try {
            BeanUtils.copyProperties(target, newMap);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return target;
    }

    //不能使用spring的BeanUtils.copyProperties，因为copy Entity的时候，copy不了父类的某些属性，如BaseEntity的id,因为id是泛型ID的类型。
    public static <T> T copyProperties(Object source, T target) {
        try {
            BeanUtils.copyProperties(target, source);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return target;
    }
}
